#include <stdio.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <signal.h>
#include <pthread.h>

// 设计设备链表节点
struct device
{
    char device_name[50]; // 设备名称
    int socket;           // 网络socket
    struct device *next;
};

struct device *head = NULL;
int client_socket = 0;

// 创建节点
struct device *create_node(char *device_name, int socket)
{
    // 创建设备节点
    struct device *new_node = (struct device *)malloc(sizeof(struct device));
    // 初始化设备节点
    strcpy(new_node->device_name, device_name);
    new_node->socket = socket;
    new_node->next = NULL;

    return new_node;
}

// 插入节点
void insert_device(struct device *head, struct device *new_node)
{
    struct device *pos = head;
    while (pos->next != NULL) // 偏移到末尾
    {
        pos = pos->next;
    }
    // 插入
    pos->next = new_node;
}

// 显示在线设备
void show_online_device(struct device *head)
{
    printf("____________当前在线设备_____________\n");

    struct device *pos = head->next;
    while (pos != NULL)
    {
        // 获取当前socket 的IP和端口
        struct sockaddr_in addr;
        int addrlen = sizeof(addr);
        getpeername(pos->socket, (struct sockaddr *)&addr, &addrlen);

        char *ip = inet_ntoa(addr.sin_addr);
        int port = ntohs(addr.sin_port);

        printf("设备名称：%s,socket:%d ip:%s port:%d\n", pos->device_name, pos->socket, ip, port);
        pos = pos->next;
    }
}



// 超时未注册
void reg_out(int arg)
{
    printf("设备超时未注册，断开连接\n");
    close(client_socket);
}


// 线程任务函数
// 读取设备信息
void *send_online_user_thread(void *arg)
{
    struct device *pos = (struct device *)arg;
    struct device *dev_p = head->next;

    while (1)
    {
        // 将用户信息发给客户端
        dev_p = head->next;
        while (dev_p!=NULL)
        { 
            write(pos->socket, dev_p, sizeof( struct device));
            dev_p = dev_p->next;   
        }

        sleep(5);
    }
}


// 线程任务函数
// 读取设备信息
void *device_thread(void *arg)
{
    struct device *pos = (struct device *)arg;
    while (1)
    {

        pthread_t ptid;
        pthread_create(&ptid, NULL, send_online_user_thread ,(void*)arg);


        char buf[1024] = {0};
        int size = read(pos->socket, buf, sizeof(buf));
        if (size <= 0)
        {
            printf("%s 设备断开连接\n", pos->device_name);
            break;
        }
        printf("设备：%s 发送数据：%s\n", pos->device_name, buf);

         // 判断是否为转发内容
        if (strstr(buf, "chat")) // chat,iphone,hello
        {
            printf("开始转发!!!!\n");

            // 找到转发的设备   c
            char h[128] = {0};
            char dev[128] = {0};
            char msg[256] = {0};
            // sscanf(buf, "%s,%s,%s", h, dev, msg);

            // printf("buf = %s\n", buf);
            // printf("h = %s\n", h);
            // printf("dev = %s\n", dev);
            // printf("msg = %s\n", msg);

            char *p1 = strtok(buf, ",");
            int i = 0;
            while (p1 != NULL)
            {

                printf("p1 = %s\n", p1);
                if(i == 0)
                    strcpy(h, p1);
                else if(i == 1)
                    strcpy(dev, p1);
                else if(i == 2)
                    strcpy(msg, p1);

                i++;
                p1 = strtok(NULL, ","); 
            }

            // 从链表中找到转发的设备
            struct device *p = head;
            while (p != NULL)
            {
                if (strstr(p->device_name, dev)) // 找到设备
                {
                    printf("找到%s设备%d,开始转发\n", p->device_name, p->socket);
                    // 发送数据
                    int size = write(p->socket, msg, strlen(msg));
                    printf("发送的数据大小 %d\n", size);
                    break;
                }

                p = p->next;
            }
        }
    }

    // 关闭socket
    close(pos->socket);

    // 从链表中删除该节点
    pthread_exit(NULL);

}

/*
    注册设备：reg,设备名
    发信息：  chat,对方的设备名,你要和他说的话

*/

// 主函数
int main(int argc, char const *argv[])
{
    // 1.创建一个头节点
    head = (struct device *)malloc(sizeof(struct device));
    head->next = NULL;

    // 2.创建一个TCP服务器
    int server_socket = socket(AF_INET, SOCK_STREAM, 0);

    // 开启端口复用功能
    int on = 1;
    setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

     // 3.绑定IP和端口
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8080);
    server_addr.sin_addr.s_addr = INADDR_ANY;
    if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        perror("bind fail:");
        return -1;
    }

    // 4.监听
    if (listen(server_socket, 10) < 0)
    {
        perror("listen fail:");
        return -1;
    }

    while (1)
    {
        // 5.接受客户端连接
        printf("等待设备注册\n");
        client_socket = accept(server_socket, NULL, NULL);
        if (client_socket < 0)
        {
            perror("accept fail:");
            continue;
        }

       
        // 6.接收设备注册名称
        printf("新设备链接等待注册设备名.....\n");
        char device_name[50] = {0};
        int ret = read(client_socket, device_name, 50);
        if (ret <= 0)
        {
            perror("设备注册失败\n");
            close(client_socket);
            continue;
        }

        
        // reg 设备名  <-  协议:  reg:协议头  设备名:协议信息 
        if (strstr(device_name, "reg"))
        {
            printf("设备注册成功\n");

            // 7.将设备信息保存到设备链表中 ,&device_name[4] 去掉 reg 头部
            struct device *xnew = create_node(&device_name[4], client_socket);
            insert_device(head, xnew);

            // 8.开启一个线程,处理该设备的消息
            pthread_t tid;
            pthread_create(&tid, NULL, device_thread, (void *)xnew);
        }
        else
        {
            printf("设备注册失败\n");
            close(client_socket);
        }

        // 9. 显示当前在线的设备
        show_online_device(head);
    }
    

    return 0;
}
